<template>
  <!-- 点光源 -->
  <!-- // 从一个点向各个方向发射的光源。 -->
  <div class="point-light">
    <div id="scene"></div>
    <div class="controls-box">
      <section>
        <el-row>
          <el-checkbox v-model="pointLightVisible">是否展示点光源</el-checkbox>
        </el-row>
        <el-row>
          <el-col :span="8" class="label-col"
            ><label> 点光源颜色</label></el-col
          >
          <el-col :span="16">
            <div class="color-select-layer">
              <el-input :value="pointLightcolor"></el-input>
              <div>
                <el-color-picker v-model="pointLightcolor"></el-color-picker>
              </div>
            </div>
          </el-col>
        </el-row>
        <el-row>
          <el-collapse accordion>
            <div>
              <el-collapse-item
                :title="item.name"
                v-for="(item, key) in pointLightProperties"
                :key="key"
              >
                <el-col
                  v-for="(paramsItem, paramsItemKey) in item.params"
                  :key="paramsItemKey"
                >
                  <el-col :span="5">
                    <span class="vertice-span">{{ paramsItem.name }}</span>
                  </el-col>
                  <el-col :span="16">
                    <el-slider
                      v-model="paramsItem.value"
                      :min="paramsItem.min"
                      :max="paramsItem.max"
                      :step="paramsItem.step"
                    ></el-slider>
                  </el-col>
                  <el-col :span="3">
                    <span class="vertice-span">{{ paramsItem.value }}</span>
                  </el-col>
                </el-col>
              </el-collapse-item>
            </div>
          </el-collapse>
        </el-row>
      </section>
    </div>
  </div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

let scene; //场景
let camera; //相机
let renderer; //创建渲染器
let controls; //控制器
let pointLight; //点光源
export default {
  name: "Scene",
  data() {
    return {
      pointLightVisible: true,
      pointLightcolor: "#ccffcc",
      pointLightProperties: {
        position: {
          name: "点光源位置-positon",
          params: {
            positionX: {
              name: "x",
              value: 14,
              min: -14,
              max: 25,
              step: 1,
            },
            positionZ: {
              name: "z",
              value: 2,
              min: -7,
              max: 7,
              step: 1,
            },
          },
        },
        intensity: {
          name: "点光源强度-intensity",
          params: {
            intensity: {
              name: "intensity",
              value: 1,
              min: 0,
              max: 5,
              step: 0.1,
            },
          },
        },
        distance: {
          name: "点光源距离-distance",
          params: {
            distance: {
              name: "distance",
              value: 10,
              min: 0,
              max: 100,
              step: 1,
            },
          },
        },
      },
    };
  },
  mounted() {
    this.createScene();
    this.createMesh();
    this.createCubeAndSphere();
    this.createLight();
    this.createSmallSphere();
    this.createCamera();
    this.createRender();
    this.render();
    this.createControls();
  },
  methods: {
    createScene() {
      //创建场景
      scene = new THREE.Scene();
    },
    // 创建网格模型
    createMesh() {
      // 创建一个平面对象PlaneGeometry
      const planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
      // 材质对象
      const planeMaterial = new THREE.MeshLambertMaterial({
        color: 0xffffff,
      });
      const plane = new THREE.Mesh(planeGeometry, planeMaterial);
      plane.receiveShadow = true;

      plane.rotation.x = -0.5 * Math.PI;
      plane.position.set(15, 0, 0);

      scene.add(plane);
    },
    // 创建方块和球
    createCubeAndSphere() {
      const geom = new THREE.BoxGeometry(4, 4, 4); // 创建几何对象geom
      const material = new THREE.MeshLambertMaterial({ color: 0xff0000 }); // 创建材质对象material
      let cube = new THREE.Mesh(geom, material); // 创建网格对象cube
      cube.castShadow = true; //对象是否被渲染到阴影贴图中。默认值为false。
      cube.position.set(-4, 3, 2);
      scene.add(cube); // 将网格对象添加到场景

      const sphereGeometry = new THREE.SphereGeometry(4, 20, 20); // 创建几何对象sphereGeometry
      const sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x7777ff }); // 创建材质对象sphereMaterial
      let sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // 创建网格对象sphere
      sphere.castShadow = true;
      sphere.position.set(20, 5, 2);
      scene.add(sphere); // 将网格对象添加到场景
    },
    createLight() {
      // 添加聚光灯
      const spotLight = new THREE.SpotLight(0xffffff);
      spotLight.position.set(-80, 60, -10);
      spotLight.castShadow = true;
      scene.add(spotLight); // 聚光灯添加到场景中
      // 环境光
      const ambient = new THREE.AmbientLight(0x0c0c0c);
      scene.add(ambient);

      pointLight = new THREE.PointLight(this.pointLightcolor);
      //设置点光源照射距离为100
      //这个距离表示从光源到光照强度为0的位置。 当设置为0时，光永远不会消失(距离无穷大)。
      pointLight.distance = 100;
      scene.add(pointLight);
    },
    // 创建小球模拟点光源发光点
    createSmallSphere() {
      const sphereLight = new THREE.SphereGeometry(0.2);
      const sphereLightMaterial = new THREE.MeshBasicMaterial({
        color: 0xac6c25,
      });
      this.sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
      this.sphereLightMesh.castShadow = true;

      this.sphereLightMesh.position.set(new THREE.Vector3(3, 0, 3));
      scene.add(this.sphereLightMesh);
    },
    createCamera() {
      const element = document.getElementById("scene");
      const width = element.clientWidth;
      const height = element.clientHeight;
      const k = width / height; //窗口宽高比
      camera = new THREE.PerspectiveCamera(45, k, 0.1, 1000);
      camera.position.set(-25, 30, 25);
      // 设置相机方向
      camera.lookAt(new THREE.Vector3(10, 0, 0));
      scene.add(camera);
    },
    // 创建渲染器
    createRender() {
      const element = document.getElementById("scene");
      renderer = new THREE.WebGLRenderer();
      // 设置渲染区域尺寸
      renderer.setSize(element.clientWidth, element.clientHeight);
      // 设置背景色
      renderer.setClearColor(0x3f3f3f, 1);
      element.appendChild(renderer.domElement);
    },
    // 更新属性
    updateFun() {
      // 点光源颜色更新
      pointLight.color = new THREE.Color(this.pointLightcolor);

      // 点光源强度更新
      pointLight.intensity =
        this.pointLightProperties.intensity.params.intensity.value;

      // 点光源距离更新
      pointLight.distance =
        this.pointLightProperties.distance.params.distance.value;

      // 点光源位置更新
      pointLight.position.set(
        this.pointLightProperties.position.params.positionX.value,
        5,
        this.pointLightProperties.position.params.positionZ.value
      );
      this.sphereLightMesh.position.copy(pointLight.position);
      // 点光源是否可见更新
      pointLight.visible = this.pointLightVisible;
    },
    render() {
      this.updateFun();
      renderer.render(scene, camera);
      // 通过requestAnimationFrame实现周期性调用render
      requestAnimationFrame(this.render);
    },
    createControls() {
      controls = new OrbitControls(camera, renderer.domElement);
    },
  },
};
</script>

<style scoped lang="less">
.point-light {
  width: 100%;
  height: 100%;
  position: relative;
}
#scene {
  width: 100%;
  height: 100%;
}
.controls-box {
  position: absolute;
  right: 5px;
  top: 5px;
  width: 300px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #c3c3c3;
}
.label-col {
  padding: 8px 5px;
  font-size: 15px;
}
.color-select-layer {
  display: flex;
}
.vertice-span {
  line-height: 38px;
  padding: 0 2px 0 10px;
}
</style>
